# -*- coding: utf-8 -*-

# Copyright (C) 2010 David Byers <david.byers@liu.se>
# 
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 3 of the License, or
# (at your option) any later version.
# 
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
# 
# You should have received a copy of the GNU General Public License along
# with this program; if not, write to the Free Software Foundation, Inc.,
# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.


from PyQt4.QtCore import *
from PyQt4.QtGui import *
from PyKDE4.plasma import *
from PyKDE4.kdeui import *

from buttons import PlaylistMoveUpButton, PlaylistMoveDownButton, PlaylistRandomizeButton, PlaylistClearButton, PlaylistRemoveButton
from actions import PlaySong

class StatusDialog(Plasma.Dialog):
    def __init__(self, client):
        Plasma.Dialog.__init__(self)
        self.client = client
        self.extended = False
        self.persistent = False
        self.setWindowFlags(Qt.FramelessWindowHint | 
                            Qt.WindowStaysOnTopHint | 
                            Qt.X11BypassWindowManagerHint)
        self.setStyleSheet("padding-left:0;color: %s;" % Plasma.Theme.defaultTheme().color(Plasma.Theme.TextColor).name())
        self.layout = QVBoxLayout(self)
        self.layout.setContentsMargins(0,0,0,10)
        self.layout.setSizeConstraint(QLayout.SetFixedSize)

        line1 = QHBoxLayout()
        line1.setContentsMargins(0,0,0,0)

        self.line1 = QLabel()
        self.line1.setAlignment(Qt.AlignLeft)

        self.line2 = QLabel()
        self.line2.setAlignment(Qt.AlignLeft)

        self.progress = QProgressBar()
        self.progress.setOrientation(Qt.Horizontal)
        self.progress.setMinimum(0)
        self.progress.setMaximum(10000)
        self.progress.setValue(0)
        self.progress.setFormat("")
        self.progress.setMaximumHeight(5)

        self.layout.addWidget(self.line1)
        self.layout.addWidget(self.line2)
        self.layout.addWidget(self.progress)

        self.current_song = -999
        self.current_playlist = -999
        self.current_state = 'init'
        self.connect(self.client, SIGNAL("status()"), self.update_status)

        self.extra = QWidget()
        layout = QVBoxLayout()
        layout.setContentsMargins(0,0,0,0)
        self.extra.setLayout(layout)

        label = QLabel()
        label.setText("Playlist")

        self.playlist = PlaylistWidget(self.client)
        self.playlist.setSortingEnabled(False)
        self.playlist.setVerticalScrollBarPolicy(Qt.ScrollBarAlwaysOn)
        self.playlist.verticalScrollBar().setTracking(True)
        self.playlist.setSelectionMode(QAbstractItemView.ExtendedSelection)
        self.playlist.setSelectionBehavior(QAbstractItemView.SelectRows)
        p = QPalette()
        p.setBrush(QPalette.Window, Qt.transparent)
        self.playlist.setPalette(p)
        self.connect(self.playlist, SIGNAL("executed(QListWidgetItem *)"), PlaySong(self.client))

        layout.addWidget(label)
        layout.addWidget(self.playlist)

        gv = QGraphicsView(self)
        gv.setContentsMargins(0,0,0,0)
        gfixed = QSizePolicy(QSizePolicy.Expanding, QSizePolicy.Minimum)
        gfixed.setHorizontalStretch(0)
        gfixed.setVerticalStretch(0)
        gfixed.setHeightForWidth(False)
        gv.setSizePolicy(gfixed)
        gv.setAutoFillBackground(True)
        gv.setStyleSheet("background: transparent;");
        gv.setFrameShape(QFrame.NoFrame)
        gv.setFrameShadow(QFrame.Plain)
        gv.setLineWidth(0)
        gv.setVerticalScrollBarPolicy(Qt.ScrollBarAlwaysOff)
        gv.setHorizontalScrollBarPolicy(Qt.ScrollBarAlwaysOff)

        gbuttons = QGraphicsWidget()
        gbuttons.setSizePolicy(gfixed)
        scene = Plasma.Corona(self)
        gv.setScene(scene)
        scene.addItem(gbuttons)
        glayout = QGraphicsLinearLayout(Qt.Horizontal, gbuttons)
        glayout.setContentsMargins(0,0,0,0)
        glayout.setSpacing(1)
        gbuttons.setLayout(glayout)

        self.up_button = PlaylistMoveUpButton(gbuttons, self.client, self.playlist)
        self.down_button = PlaylistMoveDownButton(gbuttons, self.client, self.playlist)
        self.random_button = PlaylistRandomizeButton(gbuttons, self.client)
        self.remove_button = PlaylistRemoveButton(gbuttons, self.client, self.get_selection)
        self.clear_button = PlaylistClearButton(gbuttons, self.client)

        glayout.addItem(self.up_button);
        glayout.addItem(self.down_button);
        glayout.addItem(self.random_button);
        glayout.addStretch()
        glayout.addItem(self.remove_button);
        glayout.addItem(self.clear_button);

        gv.setMaximumHeight(gbuttons.preferredSize().height())

        layout.addWidget(gv)
        self.button_container = gbuttons
        gv.resizeEvent = self.resizeButtons

    def setMinimumWidth(self, width):
        Plasma.Dialog.setMinimumWidth(self, width)
        (l,t,r,b) = self.getContentsMargins()
        self.progress.setMinimumWidth(width - l - r)

    def resizeButtons(self, event):
        self.button_container.resize(event.size().width(), self.button_container.size().height())


    def update_song(self, status):
        if not status:
            self.line1.setText("Server disconnected")
            return

        state = status.get('state','')
        cur = self.client.currentsong()
        if cur:
            pos = int(cur.get('pos',-1))
            self.playlist.hilight_item(pos)
            cur_id = cur.get('id',-1)
            if cur_id != self.current_song or state != self.current_state:
                self.current_song = cur_id
                self.current_state = state
                song = cur.get('title', "Unknown track")
                artist = cur.get('artist', '')
                album = cur.get('album', '')
                if state == 'play':
                    state = ''
                elif state == 'stop':
                    state = ' [Stopped]'
                elif state == 'pause':
                    state = ' [Paused]'
                else:
                    state = ' [' + state.capitalize() + ']'
                self.line1.setText("<b>" + song + state + "</b>")
                if artist and album:
                    self.line2.setText(artist + " - " + album)
                else:
                    self.line2.setText(artist + album)
        elif self.current_song != -1:
            self.line1.setText("Nothing playing")
            self.line2.setText("")
            self.current_song = -1

    def update_progress(self, status):
        if not status:
            self.progress.setValue(0)
            return
        else:
            try:
                (time,total) = status.get('time','0:100').split(':')
            except ValueError:
                time = 0
                total = 100
            self.progress.setValue(float(time)/float(total)*10000)

    def update_playlist(self, status):
        if not status:
            return
        playlist_id = status.get('playlist', -1)
        if playlist_id != self.current_playlist:
            self.current_playlist = playlist_id
            playlist = self.client.playlistinfo()
            self.playlist.set_playlist(playlist)

    def update_status(self):
        status = self.client.status()
        self.update_song(status)
        self.update_progress(status)
        self.update_playlist(status)

    def get_selection(self):
        return self.playlist.selectedItems()

    def set_extended(self, extended):
        if extended == self.extended:
            return
        self.extended = extended
        if extended:
            self.extra.show()
            self.layout.addWidget(self.extra)
        else:
            self.extra.hide()
            self.layout.removeWidget(self.extra)

        self.layout.update()
        #self.setMinimumSize(QSize(self.minimumWidth(), self.layout.sizeHint().height()))
        #self.setMaximumSize(QSize(self.minimumWidth(), self.layout.maximumSize().height()))
        #self.layout.setSizeConstraint(QLayout.SetMinAndMaxSize)
        #self.resize(QSize(self.minimumWidth(), self.layout.sizeHint().height()))
        #self.adjustSize()

    def is_extended(self):
        return self.extended




class PlaylistItem(QListWidgetItem):
    def __init__(self, song):
        title = song.get('title', "Unknown track")
        artist = song.get('artist', "Unknown artist")
        time = int(song.get('time', "-1"))
        time_string = None

        if time > 0:
            seconds = time % 60
            time /= 60
            minutes = time % 60
            time /= 60
            hours = time

            if hours > 0:
                time_string = "%d:%02d:%02d"%(hours,minutes,seconds)
            else:
                time_string = "%d:%02d"%(minutes,seconds)

        item_text = "%s - %s" % (artist, title)
        if time_string:
            item_text = item_text + " (" + time_string + ")"
        QListWidgetItem.__init__(self, item_text)
        self.song = song

    def __getattr__(self,attr):
        if attr.startswith("song_"):
            return self.song.get(attr[5:])
        else:
            raise AttributeError,attr



class PlaylistWidget(KListWidget):
    HILIGHT_COLOR = QColor(235, 240, 255, 255)

    def __init__(self, client):
        KListWidget.__init__(self)
        self.hilite_item = None
        self.saved_hilite = None
        self.saved_font = None
        self.client = client

    def hilight_item(self, pos):
        item = self.item(pos)
        if item == self.hilite_item:
            return
        if self.hilite_item:
            self.hilite_item.setFont(self.saved_font)
            self.hilite_item.setBackground(self.saved_hilite)
        self.hilite_item = item
        if self.hilite_item:
            self.saved_hilite = self.hilite_item.background()
            self.saved_font = self.hilite_item.font()
            font = QFont(self.saved_font)
            font.setBold(True)
            self.hilite_item.setFont(font)
            self.hilite_item.setBackground(PlaylistWidget.HILIGHT_COLOR)

    def clear(self):
        while self.count() > 0:
            self.takeItem(0)
        self.hilite_item = None

    def set_playlist(self, playlist):
        self.clear()
        if playlist:
            for song in playlist:
                item = PlaylistItem(song)
                self.addItem(item)

    def pos_after_move(self, pos, src, dst):
        if pos in src:
            before_dst = len([n for n in src if n < dst and n != pos])
            before_pos = len([n for n in src if n < pos])
            return dst - before_dst + before_pos
        else:
            if dst == pos:
                before_pos = len([n for n in src if n < pos])
                after_pos = len([n for n in src if n > pos])
                return pos + after_pos - before_pos
            elif dst > pos:
                before_pos = len([n for n in src if n < pos])
                return pos - before_pos
            elif dst < pos:
                after_pos = len([n for n in src if n > pos])
                return pos + after_pos


    def move_selection_up(self):
        self._move_selection(-1)

    def move_selection_down(self):
        self._move_selection(1)

    def _move_selection(self, dir):
        selection = self.selectedItems()
        current = self.currentItem()
        hilite = self.hilite_item

        src = sorted(selection, key=lambda song: int(song.song_pos))
        if not src: return
        if dir >= 0:
            dst = int(src[-1].song_pos) + 1
            if dst >= self.count() : dst = self.count()-1
        else:
            dst = int(src[0].song_pos) - 1
            if dst < 0: dst = 0
            src.reverse()

        for s in src:
            self.client.moveid(s.song_id, dst)

        src = [int(s.song_pos) for s in src]

        for s in src:
            pos = self.pos_after_move(s, src, dst)
            self.item(pos).setSelected(True)

        if current:
            current_pos = self.pos_after_move(int(current.song_pos), src, dst)
            self.setCurrentItem(self.item(current_pos), QItemSelectionModel.NoUpdate)

        if hilite:
            hilite_pos = self.pos_after_move(int(hilite.song_pos), src, dst)
            self.hilight_item(hilite_pos)
